/*******************************************************************************
 * Copyright 2010 Simon Mieth
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 ******************************************************************************/
package cn.kkdlk.parse.processing;

import cn.kkdlk.parse.DraftDocument;
import cn.kkdlk.parse.io.GenerationException;
import cn.kkdlk.parse.processing.helper.MergeMap;
import cn.kkdlk.parse.processing.xml.SAXFilterConfig;
import cn.kkdlk.parse.xml.SAXFilter;
import cn.kkdlk.parse.xml.SAXGenerator;
import cn.kkdlk.parse.xml.SAXSerializer;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;

import java.io.OutputStream;
import java.util.*;

public class XMLPipeline implements Generator {

    private Map<String, Object> serializerProperties = new HashMap<String, Object>();

    private SAXSerializer serializer;

    private SAXGenerator generator;
    private final List<SAXFilterConfig> saxFilterConfigs = new ArrayList<SAXFilterConfig>();
    private ProcessingManager manager;
    private final Map<String, Object> properties = new HashMap<String, Object>();

    public void generate(DraftDocument doc, Map<String, Object> context, OutputStream out)
            throws GenerationException {


        ContentHandler handler = null;
        List<Map<String, Object>> saxFilterProperties = new ArrayList<Map<String, Object>>();

        // setup saxfilters
        if (this.saxFilterConfigs.size() > 0) {
            Iterator<SAXFilterConfig> i = saxFilterConfigs.iterator();
            SAXFilterConfig sc = i.next();
            SAXFilter first = this.manager.getSAXFilter(sc.getFilterName());
            saxFilterProperties.add(new MergeMap<String, Object>(first.getProperties(), context));

            handler = first;
            first.setProperties(sc.getProperties());

            while (i.hasNext()) {
                sc = i.next();
                SAXFilter f = this.manager.getSAXFilter(sc.getFilterName());
                first.setContentHandler(f);
                saxFilterProperties.add(f.getProperties());
                f.setProperties(sc.getProperties());
                first = f;
            }
            first.setContentHandler(this.serializer);
        } else {
            // no filter
            handler = this.serializer;
        }

        Map<String, Object> oldProbs = this.serializer.getProperties();

        this.serializer.setProperties(new MergeMap<String, Object>(oldProbs, new MergeMap<String, Object>(
                this.serializerProperties, context)));

        // invoke the filter and serializer
        this.serializer.setOutput(out);

        try {
            Map<String, Object> oldGenProps = this.generator.getProperties();
            this.generator.setProperties(this.properties);
            this.generator.generate(doc, handler, context);
            // restore the old props
            this.generator.setProperties(oldGenProps);
        } catch (SAXException e) {
            throw new GenerationException(e);
        }

        // restore the serializer properties
        this.serializer.setProperties(oldProbs);

        // restore the filter properties
        for (int x = 0; x < saxFilterProperties.size(); x++) {
            SAXFilterConfig sc = saxFilterConfigs.get(x);
            this.manager.getSAXFilter(sc.getFilterName()).setProperties(
                    saxFilterProperties.get(x));
        }

    }

    public String getMimeType() {
        return this.serializer.getMimeType();
    }

    public String getSuffix() {
        return this.serializer.getSuffix();
    }

    public void setProperties(Map<String, Object> properties) {
        // FIXME Why is this not implemented?
    }

    /**
     * @return Returns the serializer.
     */
    public SAXSerializer getSAXSerializer() {
        return serializer;
    }

    /**
     * @param serializer The serializer to set.
     */
    public void setSAXSerializer(SAXSerializer serializer) {
        this.serializer = serializer;
    }

    public void setSAXGenerator(SAXGenerator generator) {
        this.generator = generator;
    }


    /**
     * @return Returns the serializerProperties.
     */
    public Map<String, Object> getSerializerProperties() {
        return serializerProperties;
    }

    /**
     * @param serializerProperties The serializerProperties to set.
     */
    public void setSAXSerializerProperties(Map<String, Object> serializerProperties) {
        this.serializerProperties = serializerProperties;
    }

}
